#!/usr/bin/env ruby

require 'optparse'

module MyDict
    def load_dict( file )

        @dict = Hash.new
        File.readlines(file).each do |line|
            k,v = line.split(':')
            @dict[k] = v.chomp
        end
    end
end

class MyTextWalker

    include MyDict

    def initialize(descriptor, max_offset)
        @descriptor = descriptor
        @buffer = ''
        @max_offset = max_offset

    end

    def get_match_lines(b)
        b = Regexp.escape(b)
        @dict.keys.select { |v| v =~ /^#{b}/ }.length
    end

    def get_match_lines_buffer
        get_match_lines @buffer
    end

    def check_full_match? 
        not @dict.keys.select { |v| v == @buffer }.empty?
    end

    def rewrite_data
        @descriptor.seek @max_offset
        o = 0

        while char = @descriptor.getc
            @descriptor.seek( o )
            @descriptor.putc char        

            o += 1
            @descriptor.seek( @max_offset + o )
        end
        o
    end

    def zero_transition
        @descriptor.seek( 0, IO::SEEK_END )
        @descriptor.write( @buffer )
        @buffer = '' 
    end

    def one_line_transition
        if check_full_match?
            
            @descriptor.seek( @offset+1 )
            sbuffer = @buffer + @descriptor.getc.chr

            unless get_match_lines( sbuffer ) > 0
                @descriptor.seek( 0, IO::SEEK_END )
                @descriptor.write( @dict[@buffer] )
                @buffer = ''
            end
        end        
    end

    def traverse
        0.upto(@max_offset-1) do |offset|
            step offset
        end
    end

    def step(offset)
        @offset = offset

        @descriptor.seek( offset )
        @char = @descriptor.getc

        @buffer += @char.chr    
        
        l = get_match_lines_buffer

        zero_transition if l == 0
        one_line_transition if l == 1

    end

    def run(dict_file)
        load_dict dict_file

        traverse

        rewrite_data
    end 
end

#raise 'challenge.rb <файл словаря> <файл для замен>' unless (ARGV[0] and ARGV[1])
options  = {}
opt_parser = OptionParser.new do |opt|
  opt.banner = "Usage: ./shr -f FILE -d DICT_FILE"
  opt.separator  ""
  opt.separator  "Replace text in FILE with values from DICT_FILE"
  opt.separator  ""
  opt.separator  "Options"

  opt.on("-f","--file FILE","mandatory file name for search and replace") do |file|
    options[:file] = file
  end

  opt.on("-d","--dict DICT_FILE","mandatory file name with pairs for replace") do |dict_file|
    options[:dict] = dict_file
  end

  opt.on("-h","--help","help") do
    puts opt_parser
    exit
  end
end

begin
    opt_parser.parse!

    dict_file = options[:dict]
    huge_file = options[:file]

    raise OptionParser::MissingArgument unless (dict_file and huge_file)

    raise "Dictionary file not found" unless File.exists? dict_file
    raise "Replacement file not found" unless File.exists? huge_file


    descriptor = File.new(huge_file, "rb+")

    max_offset = File.size(huge_file)

    walker = MyTextWalker.new(descriptor, max_offset)

    new_size = walker.run dict_file

    descriptor.close

    File.truncate( huge_file, new_size )

rescue OptionParser::MissingArgument => err
    puts err.message
    puts opt_parser
end